/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author        Notes
 */

#include <rtthread.h>

#include "drv_gpio.h"
#include "drv_digitron.h"

#define DBG_TAG "drv.digitron"
#include <drv_log.h>

static struct drv_digitron_device _digitron;

// 0~F
uint8_t digitron_ascii_map[16] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71};

void digitron_show(uint8_t data)
{
    uint8_t i = 0;

    if ((0 <= data && data < sizeof(digitron_ascii_map) / sizeof(digitron_ascii_map[0])) || 
        data == 0xFF)
    {
        for (i = 0; i < 7; i++) // 小数点做系统灯，不用处理
        {
            rt_pin_write(GET_PIN(C, i), ((digitron_ascii_map[data] >> i) & 1) == 1 ? PIN_LOW : PIN_HIGH);
        }
    } 
}

void digitron_pin_init(void)
{
    rt_pin_mode(GET_PIN(C, 0), PIN_MODE_OUTPUT);
    rt_pin_mode(GET_PIN(C, 1), PIN_MODE_OUTPUT);
    rt_pin_mode(GET_PIN(C, 2), PIN_MODE_OUTPUT);
    rt_pin_mode(GET_PIN(C, 3), PIN_MODE_OUTPUT);
    rt_pin_mode(GET_PIN(C, 4), PIN_MODE_OUTPUT);
    rt_pin_mode(GET_PIN(C, 5), PIN_MODE_OUTPUT);
    rt_pin_mode(GET_PIN(C, 6), PIN_MODE_OUTPUT);

    digitron_show(0);
}

//////////////////////////////////////////////////////////////////////////////////////////////////
static rt_err_t drv_digitron_init(rt_device_t dev)
{
    digitron_pin_init();

    return RT_EOK;
}

static rt_size_t drv_digitron_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
    RT_ASSERT(dev);
    RT_ASSERT(size <= sizeof(uint8_t));

    uint8_t data = (uint8_t)buffer;

    digitron_show(data);

    return sizeof(data);
}

static rt_err_t drv_digitron_control(rt_device_t dev, int cmd, void *args)
{
    struct drv_digitron_device *digitron = (struct drv_digitron_device *)dev;

    switch (cmd)
    {
    case DIGITRON_CTRL_SET_SHOW:
    {
        uint8_t data = (uint8_t)args;
        uint8_t i = 0;

        for (i = 0; i < 7; i++) // 小数点做系统灯，不用处理
        {
            rt_pin_write(GET_PIN(C, i), ((data >> i) & 1) == 1 ? PIN_LOW : PIN_HIGH);
        }
    }
    break;
    }

    return RT_EOK;
}

#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops digitron_ops = {
    drv_digitron_init,
    RT_NULL,
    RT_NULL,
    RT_NULL,
    drv_digitron_write,
    drv_digitron_control
};
#endif

int drv_digitron_hw_init(void)
{
    rt_err_t result = RT_EOK;
    struct rt_device *device = &_digitron.parent;

    /* memset _digitron to zero */
    rt_memset(&_digitron, 0x00, sizeof(_digitron));

    device->type = RT_Device_Class_Miscellaneous;
#ifdef RT_USING_DEVICE_OPS
    device->ops = &digitron_ops;
#else
    device->init = drv_digitron_init;
    device->write = drv_digitron_write;
    device->control = drv_digitron_control;
#endif
    device->user_data = RT_NULL;
    /* register digitron device */
    result = rt_device_register(device, "digitron", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
    if (result != RT_EOK)
    {
        LOG_E("digitron register err code: %d", result);
        return result;
    }
    LOG_I("digitron register success");

    return result;
}
INIT_DEVICE_EXPORT(drv_digitron_hw_init);

